#include "Effect.h"

Technique::Technique(ID3DX11EffectTechnique* tech)
	:m_technique(tech),
	m_pass(NULL),
	m_inputLayoutDesc(boost::make_shared<Vector<D3D11_INPUT_ELEMENT_DESC>>())
{
	m_pass = m_technique->GetPassByIndex( 0 );
	D3DX11_PASS_SHADER_DESC vertexShaderDesc;
	m_pass->GetVertexShaderDesc(&vertexShaderDesc);
	D3DX11_PASS_DESC passDesc;
	m_pass->GetDesc(&passDesc);
	vertexShaderDesc.pShaderVariable->GetShaderDesc(vertexShaderDesc.ShaderIndex,&m_effectVertexShaderDesc);
	for(int i=0;i<m_effectVertexShaderDesc.NumInputSignatureEntries;i++)
	{
		D3D11_INPUT_ELEMENT_DESC tmpInputLayout;
		D3D11_SIGNATURE_PARAMETER_DESC paramDesc;
		vertexShaderDesc.pShaderVariable->GetInputSignatureElementDesc(vertexShaderDesc.ShaderIndex,i,&paramDesc);
		tmpInputLayout.SemanticIndex=paramDesc.SemanticIndex;
		tmpInputLayout.SemanticName=paramDesc.SemanticName;
		if(strcmp(paramDesc.SemanticName,"POSITION")==0)
		{
			tmpInputLayout.AlignedByteOffset=0;
			tmpInputLayout.Format=DXGI_FORMAT_R32G32B32_FLOAT;
		}
		else
		{
			tmpInputLayout.AlignedByteOffset=12;
			tmpInputLayout.Format=DXGI_FORMAT_R32G32_FLOAT;
		}
			
		tmpInputLayout.InputSlot=0;
		tmpInputLayout.InputSlotClass=D3D11_INPUT_PER_VERTEX_DATA;
		tmpInputLayout.InstanceDataStepRate=0;
		m_inputLayoutDesc->push_back(tmpInputLayout);
	}
}

Technique::~Technique()
{
}

Technique::InputElementDescPtr Technique::GetLayoutDesc()
{
	return m_inputLayoutDesc;
}

D3DX11_EFFECT_SHADER_DESC Technique::GetVertexShaderDesc()
{
	return m_effectVertexShaderDesc;
}

void Technique::Apply(boost::shared_ptr<DeviceContext>& d)
{
	if( m_pass != 0 )
	{
		m_pass->Apply( 0, d->GetDeviceContext() );
	}
}

Effect::Effect(ID3DX11Effect* e)
	:Component(COMP_EFFECT),
	m_effect(e),
	m_deviceContext()
{
}

Effect::~Effect()
{
}

void Effect::AddedToObject()
{
	RequestComponent(COMP_DEVICE_CONTEXT,&Effect::SetDeviceContext);
}

void Effect::Initial()
{
	D3DX11_EFFECT_DESC effectDesc;
	m_effect->GetDesc(&effectDesc);
	for(UINT i=0;i<effectDesc.Techniques;i++)
	{
		ID3DX11EffectTechnique* tech=m_effect->GetTechniqueByIndex(i);
		if(tech!=NULL)
		{
			D3DX11_TECHNIQUE_DESC techDesc;
			boost::shared_ptr<Technique> tmpTech=boost::make_shared<Technique>(tech);
			tech->GetDesc(&techDesc);
			m_techniqueMap[techDesc.Name]=tmpTech;
		}
	}
}

void Effect::SetDeviceContext(const Message& msg)
{
	CompPtr tmpDeviceContext;
	AuxUnGroupArgus(msg.p,tmpDeviceContext);
	m_deviceContext=boost::shared_dynamic_cast<DeviceContext>(tmpDeviceContext);
}

Technique::InputElementDescPtr Effect::GetLayoutDesc(const string& techName)
{
	if(m_techniqueMap.find(techName)==m_techniqueMap.end())
		EXCEPTION("")
	return m_techniqueMap[techName]->GetLayoutDesc();
}

D3DX11_EFFECT_SHADER_DESC Effect::GetVertexShaderDesc(const string& techName)
{
	if(m_techniqueMap.find(techName)==m_techniqueMap.end())
		EXCEPTION("")
	return m_techniqueMap[techName]->GetVertexShaderDesc();
}

void Effect::SetMatrix(const string& matrixName, const XMMATRIX& matrix)
{
	ID3DX11EffectMatrixVariable* effectMatrix=m_effect->GetVariableByName( matrixName.c_str() )->AsMatrix();
	HRESULT hr=effectMatrix->SetMatrix((float*)(&matrix));
	CHECK_FAILED(hr)
}

void Effect::SetResource(const string& textureName, const Texture::sPtr& texture)
{
	ID3DX11EffectShaderResourceVariable* effectResource = m_effect->GetVariableByName( textureName.c_str() )->AsShaderResource();
	HRESULT hr=effectResource->SetResource( texture->GetShaderResourceView() );
	CHECK_FAILED(hr)
}

void Effect::SetSampler(const string& samplerName, ID3D11SamplerState* sampler)
{
	ID3DX11EffectSamplerVariable* effectSampler=m_effect->GetVariableByName(samplerName.c_str())->AsSampler();
	HRESULT hr=effectSampler->SetSampler(0,sampler);
	CHECK_FAILED(hr)
}

void Effect::Apply(const string& techName)
{
	if(m_techniqueMap.find(techName)==m_techniqueMap.end())
		EXCEPTION("")
	
	m_techniqueMap[techName]->Apply(m_deviceContext);
		
}

